﻿using System;
using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines.Mirrors;

using Action = Buddy.BehaviorTree.Action;

namespace WingIt.Routines
{
    // Neo93
    [RevisionControlId("$Id: Madness_Balance.cs 686 2012-08-12 16:12:20Z Chinajade $")]
    public class AssassinMadness_ShadowBalance : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Assassin, SkillTreeId.AssassinMadness)]
        [Class(CharacterClass.Consular, AdvancedClass.Shadow, SkillTreeId.ShadowBalance)]
        public static Composite AssassinMadness_ShadowBalance_Pull()
        {
            return new PrioritySelector(
                // Gates
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                // Prep
                // Casting stealth dismounts us, so it has to come before guarding companion.
                BuffSelf("Stealth"),
                CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Dark Charge")),

                // Engage
                CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee),
                Cast("Maul", maulWhen => Me.HasMirrorBuff("Stealth")),
                CastOnGround("Death Field", deathFieldOn => MyTarget.Position, deathFieldWhen => MyTarget.IsInRange(Global.Distance.Ranged)),
                AssassinMadness_ShadowBalance_Combat()
            );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Assassin, SkillTreeId.AssassinMadness)]
        [Class(CharacterClass.Consular, AdvancedClass.Shadow, SkillTreeId.ShadowBalance)]
        public static Composite AssassinMadness_ShadowBalance_Combat()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                // We may be mounted (and no Companion out) at the pull.  So, we have to wait until combat to try to apply guard.
                CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Dark Charge")),

                CreateBTPS.StopWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee),

                //***General***
                BuffSelf("Lightning Charge"),
                Cast("Unbreakable Will", unbreakableWillWhen => Me.IsStunned),
                BuffSelf("Recklessness"),
                Cast("Force Cloak", forceCloakWhen => !Me.HasMirrorBuff("Dark Embrace")),
                BuffSelf("Overcharge Saber"),

                //**Defensive**
                Cast("Deflection", deflectionWhen => Me.HealthPercent <= 80),
                Cast("Force Shroud", forceShroudWhen => Me.HealthPercent <= 70),

                //**CC**
                Cast("Whirlwind", whirlwindOn => CCTarget, whirlwindWhen => CCTarget != null),//30m

                //*Interrupts*
                // NB: These are ordered by reach of the ability (shortest reach interrupt-ability first).  This is so we don't burn
                // a far-reaching interrupt on a target that is standing next to us.
                // TODO: Why would this not be used?: Cast("Low Slash", lowSlashOn => InterruptTarget, lowSlashWhen => TargetSelect.ForInterrupt(c => c.IsInRange(0.4f)) != null),//4m
                Cast("Overload", overloadOn => InterruptTarget, overloadWhen => (Me.MobCountAround(Global.Distance.MeleeAoE) >= 3) && TargetSelect.ForInterrupt(c => c.IsInRange(0.8f)) != null),//8m
                Cast("Jolt", joltOn => InterruptTarget, joltWhen => TargetSelect.ForInterrupt(c => c.IsInRange(1f)) != null),//10m
                Cast("Electrocute", electrocuteOn => InterruptTarget, electrocuteWhen => TargetSelect.ForInterrupt(c => c.IsInRange(3f)) != null),//30m

                //Rotation
                Cast("Maul", maulWhen => Me.HasMirrorBuff("Stealth")),
                CastOnGround("Death Field", deathFieldOn => MyTarget.Position, deathFieldWhen => MyTarget.IsInRange(Global.Distance.Ranged)),
                Cast("Crushing Darkness", crushingDarknessWhen => Me.HasMirrorBuff("Raze") && !MyTarget.HasMirrorDebuff("Crushed (Force)")),
                Cast("Discharge", dischargeWhen => !MyTarget.HasMirrorDebuff("Shocked (Force)")),
                Cast("Assassinate", assassinateWhen => MyTarget.HealthPercent <= 30),
                Cast("Creeping Terror", creepingTerrorWhen => !MyTarget.HasMirrorDebuff("Creeping Terror (Force)")),
                Cast("Maul", maulWhen => Me.HasMirrorBuff("Exploit Weakness")),
                Cast("Lacerate", lacerateWhen => Me.MobCountAround(Global.Distance.Melee) >= 3),
                Cast("Thrash", thrashWhen => Me.ResourceStat > 45),
                Cast("Saber Strike"),

                //Movement
                CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Melee)
            );
        }

        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Assassin, SkillTreeId.AssassinMadness)]
        [Class(CharacterClass.Consular, AdvancedClass.Shadow, SkillTreeId.ShadowBalance)]
        public static Composite AssassinMadness_ShadowBalance_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return (new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        BuffSelf("Force Speed", forceSpeedWhen => Me.IsMoving),
                        BuffSelf("Lightning Charge"),
                        CreateBTPS.ApplyGuard(applyGuardWhen => Me.HasMirrorBuff("Dark Charge"))
                        ))
                ));
        }
    }
}